Verilog Tutorial(6)如何编写一个基础的Testbench

您所在的位置:网站首页 test bench是什么意思 Verilog Tutorial(6)如何编写一个基础的Testbench

Verilog Tutorial(6)如何编写一个基础的Testbench

2023-09-08 17:23| 来源: 网络整理| 查看: 265

写在前面

在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。

这是网站原文:https://fpgatutorial.com/verilog/

这是系列导航:Verilog教程系列文章导航

本文将讲述如何使用Verilog 编写一个基础的测试脚本(testbench)。

在考虑一些关键概念之前,先来看看testbench的架构是什么样的。架构包括建模时间、initial块(initial block)和任务(task)。此文最后将以一个完整的testbench编写作为示例。

在使用verilog设计数字电路时,设计人员通常还会创建一个testbench来仿真代码以确保其按预期设计运行。设计人员可以使用多种语言构建testbench,其中最流行的是VHDL、Verilog和System verilog。

System Verilog 在行业中被广泛应用,可能是用于测试的最常用语言,但本文仅介绍 verilog 中testbench设计的基本原则。

1、Testbench的架构

testbench由不可综合的verilog 代码组成,这些代码生成被测设计的输入并验证被测设计的输出是否正确(输出是否符合预期)。

下图展示了一个基本testbench的典型架构。

激励(stimulus block)是为 FPGA 设计生成的输入

输出校验(output checker)检查被测模块的输出是否符合预期

被测模块(design under test,DUT)即是编写的verilog模块,testbench的主要设计目的就是对其进行验证,以确保在特定输入下,其输出均与预期一致

对于较大规模的设计,激励和输出校验可以位于单独的文件中,也可以将所有这些不同的模块都包含在同一个文件中。

2、例化被测模块

编写testbench的第一步是创建一个 verilog 模块作为测试的顶层。

与讨论过的verilog module不同,在这种情况下,设计人员要创建的是一个没有输入和输出的模块。这是因为设计人员希望testbench模块是完全独立的(self contained)。

下面的代码片段展示了一个空模块的语法,这可以被用作testbench。

module (); //在这里写testbench endmodule :

创建了一个testbench之后,必须例化被测设计,这可以将信号连接到被测设计以激励代码运行。

下面的代码片段展示了如何例化一个被测模块。

# ( //例化参数 . () ) ( //连接端口信号 . (), . (signal_name>) );

完成此操作后,就可以开始将激励写入testbench。激励包括时钟信号和复位信号,以及创建发送到testbench的测试数据。

为此,需要使用一些尚未学过的 verilog 结构----initial块(initial block)、foever循环(foever loop)和时间控制(time consuming)语句。

3、Verilog 中的建模时间(Modelling Time)

testbench代码和设计代码之间的主要区别是testbench并不需要被综合成实际电路,为此可以使用时间控制语句这种特殊结构。事实上,这对于创建测试激励至关重要。

在 Verilog 中有一个可用的结构----它能够对仿真进行延时。在 verilog 中使用 # 字符后跟多个时间单位来模拟延时。

例如,下面的 verilog 代码展示使用延时运算符等待 10 个时间单位。

#10

这里要注意的是代码末尾并没有分号。

将延时语句写在与赋值相同的代码行中也很常见,这可以有效地行使调度功能,将信号的变化安排在延迟时间之后。下面的代码片段是此种情况的一个示例。

#10 a = 1'b1; // 在10个时间单位后,a将被赋值为1

3.1、时间单位(Timescale )编译指令

在上一节已经讨论了十个时间单位的延时用法,但在设计人员真正定义所使用的时间单位之前,这样的讨论是毫无意义的。

为了指定在仿真期间所使用的时间单位,需要使用指定时间单位和时间精度(分辨率)的 verilog 编译器指令。这只需要在testbench中运行该指令一次,而且应在模块外完成。

下面的代码片段展示用来在 verilog 中指定时间单位和精度的编译指令。

`timescale /

指定时间的单位,则指定时间精度。

很重要,因为设计人员可以使用小数来指定 verilog 代码中的延时。例如,如果设计人员想要 10.5ns 的延迟,就可以简单地写为 #10.5。因此,编译指令中的 决定了可以实现最小时间的步长(即精度)。

此编译指令中的两个参数都采用时间类型,例如 1ps 或 1ns。

4、Verilog initial block(初始块)

在initial 块中编写的任何代码都会在仿真开始时执行一次且仅执行一次。

下面的 verilog 代码展示了initial 块的一般语法。

initial begin //这里写代码 end

与 always 块不同,在 initial 块中编写的 verilog 代码几乎是不可综合的,因此其几乎只被用于仿真。但是,在verilog RTL 中也可以使用initial块来初始化信号(几乎很少用)。

为了更好地理解如何使用initial块在 verilog 中编写激励,请来看一个基本示例----假设现在想要测试一个基本的两输入与门,为此需要编写代码来生成所有可能的四种输入。此外还需要使用延时运算符以在生成不同的输入之间延迟一段时间。这很重要,因为这可以允许信号有时间来传播。

下面的 verilog 代码展示了在initial块中编写此测试的方法。

initial begin // 每隔10个时间单位就生成一个输入 and_in = 2b'00; #10 and_in = 2b'01; #10 and_in = 2b'10; #10 and_in = 2b'11; end 5、Verilog Foever 循环(Loop)

在 verilog testbench中可以使用一种重要的循环类型——foever循环。

使用这个构造时,实际上是创建了一个无限的循环----这意味着创建了一段在仿真过程中将永远运行的代码。

下面的 verilog 代码展示了用来编写foever循环的一般语法。

forever begin // our code goes here end

当用其他编程语言编写代码时,无限循环一般被视为应极力避免的严重错误。但是,verilog 与其他编程语言不同,编写 verilog 代码是在描述硬件而不是在编写软件。

因此,至少有一种情况是可以使用无限循环的----时钟信号。为此需要一种定期连续反转信号的方法,foever循环与此相当契合。

下面的 verilog 代码展示了如何使用foever循环在testbench中生成一个时钟。需要注意的是,所编写的任何循环都必须包含在过程块(procedural block)中或生成块(generate块)中。

initial begin clk = 1'b0; forever begin #1 clk = ~clk; end end 6、Verilog 系统任务(System Tasks)

在 verilog 中编写testbench时,有一些内置的任务和函数可以提供帮助。这些被统称为系统任务或系统函数,它们很容易被识别----总是以美元符号($)开头。

虽然有很多这样的系统任务可用,但是这三个是最常用的 :$display、$monitor 和 $time。

6.1、$display

$display 是 verilog 中最常用的系统任务之一。设计人员可以使用它来输出一条消息,该消息在仿真时将会显示在控制台上。

$display的使用方式与C语言中的printf函数非常类似,这意味着设计人员可以轻松地在testbench中创建文本语句,并使用它们来显示有关仿真状态的信息。

设计人员还可以在字符串中使用特殊字符 (%) 来显示设计中的信号。这样做时,还必须使用一个格式字母来决定以何种格式显示变量。最常用的格式是 b(二进制)、d(十进制)和 h(十六进制)。设计人员还可以在这个格式代码前面加上一个数字来确定要显示的位数。

下面的 verilog 代码展示了 $display 系统任务的一般语法。此代码片段还包括一个示例用例。

//一般语法 $display(,


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3